package com.yeskery.nut.cloud.registry.core;

import com.yeskery.nut.application.ServerEventContext;
import com.yeskery.nut.core.Environment;
import com.yeskery.nut.core.NutException;
import com.yeskery.nut.plugin.ServerEventPlugin;
import com.yeskery.nut.util.IPUtils;
import com.yeskery.nut.util.StringUtils;

import java.util.Collection;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Logger;

/**
 * 默认内置注册器
 * @author YESKERY
 * 2024/1/4
 */
public class DefaultServerRegistry implements ServerRegistry, ServerEventPlugin {

    /** 日志对象 */
    private static final Logger logger = Logger.getLogger(DefaultServerRegistry.class.getName());

    /** 本机ip */
    private static final String LOCALHOST_IP = "127.0.0.1";

    /** 协议头key */
    private static final String SCHEME_KEY = "nut.cloud.registry.scheme";

    /** ip key */
    private static final String IP_KEY = "nut.cloud.registry.ip";

    /** 端口号key */
    private static final String PORT_KEY = "nut.cloud.registry.port";

    /** 递增器 */
    private final AtomicInteger atomic = new AtomicInteger(0);

    /** 服务map */
    private final Map<String, Server> serverMap = new ConcurrentHashMap<>(16);

    /** 服务事件上下文 */
    private ServerEventContext serverEventContext;

    @Override
    public Server getServer(String name) {
        return serverMap.get(name);
    }

    @Override
    public Collection<Server> getServers() {
        return serverMap.values();
    }

    @Override
    public Server registerServer(ServerMetadata metadata) {
        if (metadata == null) {
            throw new NutException("Server Metadata Must Not Be Null.");
        }
        Server server = serverMap.get(metadata.getName());
        if (server != null) {
            throw new NutException("Server[" + metadata.getName() + "] Already Registered.");
        }
        DefaultServer defaultServer = new DefaultServer();
        defaultServer.setId(String.valueOf(atomic.incrementAndGet()));
        defaultServer.setServerMetadata(metadata);
        DefaultServerInstanceRegistry defaultServerInstanceRegistry = new DefaultServerInstanceRegistry();
        defaultServerInstanceRegistry.setServer(defaultServer);
        defaultServer.setServerInstanceRegistry(defaultServerInstanceRegistry);
        serverMap.put(metadata.getName(), defaultServer);
        logger.info("Server[" + metadata.getName() + "] Registered.");
        return defaultServer;
    }

    @Override
    public void removeServer(String name) {
        serverMap.remove(name);
    }

    @Override
    public void beforeClose(ServerEventContext serverEventContext) {
        serverMap.clear();
    }

    @Override
    public void beforeStart(ServerEventContext serverEventContext) {
        this.serverEventContext = serverEventContext;
    }

    /**
     * 获取服务map
     * @return 服务map
     */
    protected Map<String, Server> getServerMap() {
        return serverMap;
    }

    /**
     * 获取当前的服务名称
     * @param environment 环境对象
     * @return 服务名称
     */
    protected String getCurrentApplicationName(Environment environment) {
        String applicationName = environment.getEnvProperty("nut.application.name");
        if (StringUtils.isEmpty(applicationName)) {
            applicationName = UUID.randomUUID().toString();
        }
        return applicationName;
    }

    /**
     * 获取当前的服务元数据
     * @param environment 环境对象
     * @return 当前的服务元数据
     */
    protected ServerMetadata getCurrentServerMetadata(Environment environment) {
        DefaultServerMetadata defaultServerMetadata = new DefaultServerMetadata();
        defaultServerMetadata.setName(getCurrentApplicationName(environment));
        defaultServerMetadata.setRegisterTime(System.currentTimeMillis());
        defaultServerMetadata.setLatestUpdateTime(defaultServerMetadata.getRegisterTime());
        return defaultServerMetadata;
    }

    /**
     * 获取当前的服务实例元数据
     * @param environment 环境对象
     * @return 当前的服务实例元数据
     */
    protected ServerInstanceMetadata getCurrentServerInstanceMetadata(Environment environment) {
        DefaultServerInstanceMetadata defaultServerInstanceMetadata = new DefaultServerInstanceMetadata();
        String scheme = environment.getEnvProperty(SCHEME_KEY);
        if (StringUtils.isEmpty(scheme)) {
            scheme = serverEventContext.getApplicationMetadata().isSecureServer() ? "https://" : "http://";
        }
        String ip = environment.getEnvProperty(IP_KEY);
        if (StringUtils.isEmpty(ip)) {
            ip = IPUtils.getAllLocalIp().values()
                    .stream()
                    .flatMap(Collection::stream)
                    .filter(r -> !r.equals(LOCALHOST_IP))
                    .findFirst()
                    .orElse(LOCALHOST_IP);
        }
        String port = environment.getEnvProperty(PORT_KEY);
        defaultServerInstanceMetadata.setPort(StringUtils.isEmpty(port)
                ? serverEventContext.getApplicationMetadata().getServerPort()
                : Integer.parseInt(port));
        defaultServerInstanceMetadata.setScheme(scheme);
        defaultServerInstanceMetadata.setIp(ip);
        defaultServerInstanceMetadata.setStatus(ServerInstanceStatus.OK);
        return defaultServerInstanceMetadata;
    }
}
